<?php

/**
 * Файловый драйвер кэширования
 * 
 * @package Progmatic
 * @author Ladygin Sergey
 * @copyright 2009 Ladygin Sergey
 */
class FileDriver implements CacheInterface {
    
    /**
     * Путь до папки с кэшем
     * @var string
     */
    private $directory = 'cache/';
    
    /**
     * Расширение файлов кэша
     * @var string
     */
    private $ext = '.cache';
    
    
    /**
     * Конструктор
     * @param string $directory Путь до папки с кэшем
     * @return void
     */
    public function __construct($directory = NULL) {
        
        if($this->setDirectory($directory)) {
            
            if(!$this->checkDirectory($this->directory)) {
                    
                throw new CacheException('Unable to use given directory. Check file permissions.');
            }
        }
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#set($group, $identifier, $data)
     */
    public function set($group, $identifier, $data) {
        
        if(!$this->checkDirectory($this->createPath($group))) {
            
            return false;
        }
        
        return file_put_contents($this->createPath($group, $identifier), $data, LOCK_EX) === false ? false : true;
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#get($group, $identifier)
     */
    public function get($group, $identifier) {
        
        return file_get_contents($this->createPath($group, $identifier));
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#clear($group, $identifier)
     */
    public function clear($group, $identifier) {
        
        @unlink($this->createPath($group, $identifier));
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#clearGroup($group)
     */
    public function clearGroup($group) {
        
        $this->deleteDir($this->createPath($group));
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#clearAll()
     */
    public function clearAll() {
        
        $this->deleteDir($this->directory, true);
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#modificationTime($group, $identifier)
     */
    public function modificationTime($group, $identifier) {
        
        return filemtime($this->createPath($group, $identifier));
    }
    
    
    /* (non-PHPdoc)
     * @see application/libraries/drivers/CacheInterface#exists($group, $identifier)
     */
    public function exists($group, $identifier) {
        
        return is_file($this->createPath($group, $identifier));
    }
    
    
    /**
     * Установка дериктории с кэшем
     * Осуществляется провека существует ли директория и возможна
     * ли в неё запись.
     * @param string $directory Путь до папки с кэшем
     * @return boolean
     */
    public function setDirectory($directory = NULL) {
        
        if(!empty($directory) && $this->checkDirectory($directory)) {
            
            $this->directory = $directory;
            return true;
        }
        
        return false;
    }
    
    
    /**
     * Проверка директории
     * @param string $directory
     * @return boolean
     */
    private function checkDirectory($directory) {
        
        if(!is_dir($directory) && mkdir($directory, 0777) == false) {
            
            return false;
        }
        
        if(!is_writable($directory) && chmod($directory, 0777) == false) {
            
            return false;
        }
        
        return true;
    }
    
    
    /**
     * Создание пути до файла кэша
     * @param string $group Папка
     * @param string $identifier Индентификатор
     * @return string
     */
    private function createPath($group, $identifier = NULL){
        
        return $this->directory.$group.'/'.(empty($identifier) ? '' : $identifier.$this->ext);
    }
    
    
    /**
     * Удаление дериктории или файлов в директориях
     * @param string $directory Папка
     * @param boolean $contentOnly Удалять только контент или папку тоже
     */
    private function deleteDir($directory, $contentOnly = false) {
        
        if ( ! $currentDir = @opendir($directory)) {
        
            return;
        }

        while(FALSE !== ($fileName = @readdir($currentDir))) {
            
            if ($fileName != "." && $fileName != "..") {

                if (is_dir($directory.$fileName)) {
                    
                    $this->deleteDir($directory.$fileName.'/');
                }
                else {
                    
                    unlink($directory.$fileName);
                }
            }
        }
        
        @closedir($currentDir);

        if(!$contentOnly) @rmdir($directory);
    }
}